import { EnumBjlResult } from "@/models/enums/EnumBjlResult";
import { ExcutePlan, RecmInfo, RoundInfo } from "../ExecutePlan";
import { IPlan } from "../IExecutePlan";
import { FollowResultStrategy, FollowStrategy } from "./FollowStrategy";
import { IRecmStrategy } from "../IRecmStrategy";


export interface IWisdomOption {
    subPlan: IPlan[];
}
/**
 * AI智能策略
 */
export class WisdomRecmStrategy implements IRecmStrategy {

    subPlan: IPlan[] = [];
    strategyName: string = "WisdomRecmStrategy";
    debugCompoenent: string = "WisdomRecmStrategyDebug";
    selectPlan: IPlan[] = [];
    recmV: EnumBjlResult = EnumBjlResult.U;
    constructor(name?: string, count?: number) {
        if (!count) {
            count = 500;
        }
        this.strategyName = name ?? "";
        this.recmV = EnumBjlResult.U;
        let roundInfo = new RoundInfo();
        for (let idx = 0; idx < count; idx++) {
            let pp_plan = new ExcutePlan();
            pp_plan.recmStrategy = [new FollowStrategy({ followCount: (idx + 1), reverse: false })];
            pp_plan.planName = `规则 ${idx + 1} `;
            pp_plan.recmInfo.recmV = pp_plan.toResult(roundInfo);
            pp_plan.userRecmInfo.recmV = pp_plan.recmInfo.recmV;
            this.subPlan.push(pp_plan);
        }
    }
    resetRecm(): void {
        this.subPlan.forEach(item => {
            item.recmStrategy.forEach(rs => rs.resetRecm());
            item.moneyStrategy.forEach(ms => ms.resetRecm());
        })
    }
    copyValue(valueObj: any): void {
        let obj = valueObj as WisdomRecmStrategy;
        if (obj) {
            this.recmV = obj.recmV;
            for (let i = 0; i < this.subPlan.length; i++) {
                this.subPlan[i].copyValue(obj.subPlan[i]);
            }
            this.selectPlan = obj.selectPlan;
        }

    }
    setOption<T>(option: T): void {
        let op = option as IWisdomOption;
        if (op && op.subPlan) {
            this.subPlan = op.subPlan;
        }
    }
    setResult(roundInfo: RoundInfo, recmInfo: RecmInfo, multiple: number, waterRate: number, fuliRate: number): void {
        let recmMoney = recmInfo.recmMoney;
        if (multiple > 0) {
            recmMoney = recmMoney * multiple;
        }
        this.subPlan.forEach(pl => {
            let plan = pl as ExcutePlan;
            plan.setResult(roundInfo, plan.recmInfo, plan.multiple, plan.waterRate, plan.fuliRate);
        });

    }
    toResult(roundInfo: RoundInfo): EnumBjlResult {
        let planArray: IPlan[] = [];
        let max = 1;
        this.subPlan.forEach(pl => {
            pl.userRecmInfo.recmV = pl.toResult(roundInfo);
            if (pl.userRecmInfo.summaryInfo.lfail > 0 && pl.userRecmInfo.recmV != EnumBjlResult.U) {
                pl.recmInfo.recmV = pl.userRecmInfo.recmV == EnumBjlResult.Z ? EnumBjlResult.X : EnumBjlResult.Z;
            }
            else {
                pl.recmInfo.recmV = pl.userRecmInfo.recmV;
            }
            let plan = pl as ExcutePlan;
            //let mv = plan.userRecmInfo.summaryInfo.lwin > plan.userRecmInfo.summaryInfo.lfail ? plan.userRecmInfo.summaryInfo.lwin : plan.userRecmInfo.summaryInfo.lfail;

            let mv = Math.abs(plan.userRecmInfo.summaryInfo.lwin - plan.userRecmInfo.summaryInfo.lfail);

            if (mv > 0) {
                if (mv > max) {
                    max = mv;
                    planArray = [plan];
                }
                else if (mv < max) {
                }
                else {
                    planArray.push(plan);
                }
            }
        });
        let iv = 0;
        this.selectPlan = planArray;

        // if (planArray.length > 0) {
        //     this.subPlan.forEach(pl => {
        //         if (planArray.filter(x => x.planName == pl.planName).length > 0) {

        //         }
        //         else {
        //             pl.resetPlanSummaryInfo();
        //         }
        //     });
        // }
        let recmV = EnumBjlResult.U;
        if (planArray.length > 0) {
            planArray.forEach(item => {
                let plan = item as ExcutePlan;
                if (!plan) return;
                if (plan.recmInfo.recmV == EnumBjlResult.Z) {
                    iv++;
                }
                else if (plan.recmInfo.recmV == EnumBjlResult.X) {
                    iv--;
                }
            });
        }
        if (iv > 0) recmV = EnumBjlResult.Z;
        else if (iv < 0) recmV = EnumBjlResult.X;
        else recmV = EnumBjlResult.U;
        this.recmV = recmV;
        return recmV;
    }

}

export class WisdomFollowResultStrategy implements IRecmStrategy {
    subPlan: IPlan[] = [];
    strategyName: string = "WisdomFollowStrategy";
    debugCompoenent: string = "WisdomFollowResultRecmStrategyDebug";
    selectIndex: number = -1;
    recmV: EnumBjlResult = EnumBjlResult.U;
    displayRate: number = 0;
    constructor(name?: string, count?: number) {
        if (!count) {
            count = 500;
        }
        this.strategyName = name ?? "";
        this.recmV = EnumBjlResult.U;
        let roundInfo = new RoundInfo();
        this.selectIndex = -1;
        this.displayRate = 0;
        for (let idx = 0; idx < count; idx++) {
            let pp_plan = new ExcutePlan();
            pp_plan.recmStrategy = [new FollowResultStrategy({ followCount: (idx + 1), reverse: false })];
            pp_plan.planName = `规则 ${idx + 1} `;
            pp_plan.recmInfo.recmV = pp_plan.toResult(roundInfo);
            pp_plan.userRecmInfo.recmV = pp_plan.recmInfo.recmV;
            this.subPlan.push(pp_plan);
        }
    }

    resetRecm(): void {
        this.subPlan.forEach(item => {
            item.recmStrategy.forEach(rs => rs.resetRecm());
            item.moneyStrategy.forEach(ms => ms.resetRecm());
        })
    }
    copyValue(valueObj: any): void {
        let obj = valueObj as WisdomFollowResultStrategy;
        if (obj) {
            this.recmV = obj.recmV;
            this.selectIndex = obj.selectIndex;
            this.displayRate = obj.displayRate;

            for (let i = 0; i < this.subPlan.length; i++) {
                this.subPlan[i].copyValue(obj.subPlan[i]);
            }
        }

    }
    setResult(roundInfo: RoundInfo, recmInfo: RecmInfo, multiple: number, waterRate: number, fuliRate: number): void {
        let recmMoney = recmInfo.recmMoney;
        if (multiple > 0) {
            recmMoney = recmMoney * multiple;
        }
        this.subPlan.forEach(pl => {
            let plan = pl as ExcutePlan;
            plan.setResult(roundInfo, plan.recmInfo, plan.multiple, plan.waterRate, plan.fuliRate);
        });

    }
    toResult(roundInfo: RoundInfo): EnumBjlResult {
        let recmV = EnumBjlResult.U;

        let selectRate = 0;
        if (this.selectIndex >= 0) {
            let selectMv = Math.abs(this.subPlan[this.selectIndex].userRecmInfo.summaryInfo.winCount
                - this.subPlan[this.selectIndex].userRecmInfo.summaryInfo.failCount);
            let selectSum = (this.subPlan[this.selectIndex].userRecmInfo.summaryInfo.winCount
                + this.subPlan[this.selectIndex].userRecmInfo.summaryInfo.failCount);
            if (selectSum > 0) {
                selectRate = selectMv / selectSum;
            }
        }

        let max = 0;
        let maxSum = 0;
        let maxRate = 0;
        let index = -1;
        let imaxRate = 0;

        this.subPlan.forEach((pl, idx) => {
            pl.userRecmInfo.recmV = pl.toResult(roundInfo);
            if (pl.userRecmInfo.summaryInfo.winCount > pl.userRecmInfo.summaryInfo.failCount
                && pl.userRecmInfo.recmV != EnumBjlResult.U) {
                pl.recmInfo.recmV = pl.userRecmInfo.recmV == EnumBjlResult.Z ? EnumBjlResult.X : EnumBjlResult.Z;
            }
            else {
                pl.recmInfo.recmV = pl.userRecmInfo.recmV;
            }
            let plan = pl as ExcutePlan;

            let mv = Math.abs(plan.userRecmInfo.summaryInfo.winCount - plan.userRecmInfo.summaryInfo.failCount);
            let sum = (plan.userRecmInfo.summaryInfo.winCount + plan.userRecmInfo.summaryInfo.failCount)
            let rate = 0;
            if (sum > 0) {
                rate = mv / sum;
            }
            if (rate > imaxRate && rate !=1 && sum >= 60) {
                imaxRate = (plan.userRecmInfo.summaryInfo.winCount - plan.userRecmInfo.summaryInfo.failCount) / sum;
            }

            if (rate > 0.3 && sum >= 60) {
                if (rate > max) {
                    max = rate;
                    //planArray = [plan];
                    index = idx;
                    maxSum = sum;
                    maxRate = rate;
                }
                else if (rate < max) {
                }
                else {
                    if (sum > maxSum) {
                        max = rate;
                        index = idx;
                        maxSum = sum;
                        maxRate = rate;
                    }
                }
            }
        });
        let iv = 0;

        if (index >= 0 && (maxRate - selectRate) > 0.1) {
            this.selectIndex = index;
        }

        if (this.selectIndex >= 0) {
            recmV = this.subPlan[this.selectIndex].recmInfo.recmV;
            imaxRate = (this.subPlan[this.selectIndex].userRecmInfo.summaryInfo.winCount 
            - this.subPlan[this.selectIndex].userRecmInfo.summaryInfo.failCount)
            / (this.subPlan[this.selectIndex].userRecmInfo.summaryInfo.winCount 
                + this.subPlan[this.selectIndex].userRecmInfo.summaryInfo.failCount);
        }
        this.displayRate = imaxRate;
        this.recmV = recmV;
        return recmV;
    }
}


export class WisdomRecmWinFailStrategy extends WisdomRecmStrategy {
    protected _diff: number;
    constructor(name?: string, count?: number, diff?: number) {
        super(name, count);
        this._diff = diff ?? 50;
    }

    toResult(roundInfo: RoundInfo): EnumBjlResult {
        let planArray: IPlan[] = [];

        this.subPlan.forEach(pl => {
            pl.userRecmInfo.recmV = pl.toResult(roundInfo);

            let wfr = pl.userRecmInfo.summaryInfo.winCount - pl.userRecmInfo.summaryInfo.failCount;
            if (Math.abs(wfr) >= this._diff) {
                planArray.push(pl);
            }

            if (pl.userRecmInfo.summaryInfo.winCount > pl.userRecmInfo.summaryInfo.failCount && pl.userRecmInfo.recmV != EnumBjlResult.U) {
                pl.recmInfo.recmV = pl.userRecmInfo.recmV == EnumBjlResult.Z ? EnumBjlResult.X : EnumBjlResult.Z;
            }
            else {
                pl.recmInfo.recmV = pl.userRecmInfo.recmV;
            }
        });
        let iv = 0;
        this.selectPlan = planArray;

        if (planArray.length > 0) {
            planArray.forEach(item => {
                let plan = item as ExcutePlan;
                if (!plan) return;
                if (plan.recmInfo.recmV == EnumBjlResult.Z) {
                    iv++;
                }
                else if (plan.recmInfo.recmV == EnumBjlResult.X) {
                    iv--;
                }
            });
        }
        if (iv > 0) return EnumBjlResult.Z;
        else if (iv < 0) return EnumBjlResult.X;
        else return EnumBjlResult.U;

    }
}

export class WisdomRecmCumulativeStrategy extends WisdomRecmStrategy {
    protected _winSum: number = 0;
    protected _failSum: number = 0;
    public get winSum() {
        return this._winSum;
    }
    public get failSum() {
        return this._failSum;
    }
    constructor(name?: string, count?: number) {
        super(name, count);
        this._winSum = 0;
        this._failSum = 0;
    }

    toResult(roundInfo: RoundInfo): EnumBjlResult {
        let planArray: IPlan[] = [];

        let winCount = 0;
        let failCount = 0;
        let winPlan: IPlan[] = [];
        let failPlan: IPlan[] = [];
        this.subPlan.forEach(pl => {
            pl.userRecmInfo.recmV = pl.toResult(roundInfo);
            if (pl.userRecmInfo.summaryInfo.winCount < pl.userRecmInfo.summaryInfo.failCount && pl.userRecmInfo.recmV != EnumBjlResult.U) {
                pl.recmInfo.recmV = pl.userRecmInfo.recmV == EnumBjlResult.Z ? EnumBjlResult.X : EnumBjlResult.Z;
            }
            else {
                pl.recmInfo.recmV = pl.userRecmInfo.recmV;
            }
            if (pl.userRecmInfo.summaryInfo.winCount > pl.userRecmInfo.summaryInfo.failCount) {
                winCount += (pl.userRecmInfo.summaryInfo.winCount - pl.userRecmInfo.summaryInfo.failCount);
                winPlan.push(pl);
            }
            else if (pl.userRecmInfo.summaryInfo.failCount > pl.userRecmInfo.summaryInfo.winCount) {
                failCount += (pl.userRecmInfo.summaryInfo.failCount - pl.userRecmInfo.summaryInfo.winCount);
                failPlan.push(pl);
            }
        });
        if (winCount > failCount) {
            planArray = failPlan;
        }
        else if (winCount < failCount) {
            planArray = winPlan;
        }
        let iv = 0;
        this.selectPlan = planArray;
        this._winSum = winCount;
        this._failSum = failCount;

        if (planArray.length > 0) {
            planArray.forEach(item => {
                let plan = item as ExcutePlan;
                if (!plan) return;
                if (plan.recmInfo.recmV == EnumBjlResult.Z) {
                    iv++;
                }
                else if (plan.recmInfo.recmV == EnumBjlResult.X) {
                    iv--;
                }
            });
        }
        if (iv > 0) return EnumBjlResult.Z;
        else if (iv < 0) return EnumBjlResult.X;
        else return EnumBjlResult.U;

    }
    copyValue(valueObj: any): void {
        super.copyValue(valueObj);
        let obj = valueObj as WisdomRecmCumulativeStrategy;
        if (obj) {
            this._winSum = obj._winSum;
            this._failSum = obj._failSum;
            for (let i = 0; i < this.subPlan.length; i++) {
                this.subPlan[i].copyValue(obj.subPlan[i]);
            }
            this.selectPlan = obj.selectPlan;
        }

    }
}